home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / gtlayout / source / gtlayout_lib.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  22KB  |  710 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1998 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. /*****************************************************************************/
  15.  
  16. #include <exec/execbase.h>
  17. #include <exec/resident.h>
  18.  
  19. #include <dos/dos.h>    /* For BPTR definition */
  20.  
  21. /*****************************************************************************/
  22.  
  23. #include "Assert.h"
  24.  
  25. #include "gtlayout.library_rev.h"
  26.  
  27. /*****************************************************************************/
  28.  
  29. /****** gtlayout.library/--version-- ******************************************
  30. *
  31. *   NOTES
  32. *    This document describes gtlayout.library v5.12 or higher. Do not assume that
  33. *    previous library releases support the same features.
  34. *
  35. ******************************************************************************
  36. *
  37. */
  38.  
  39. /****** gtlayout.library/--background-- ******************************************
  40. *
  41. *   NOTES
  42. *    1. General information
  43. *
  44. *    1.1 Purpose
  45. *
  46. *    The GUI code included in this archive helps to create user interfaces
  47. *    using gadtools.library with a minimum of effort. The code
  48. *    automatically takes care of the font to be used, making the user
  49. *    interface font independent. Localizing support is built right into
  50. *    the code, just install a callback hook and pass numeric IDs for the
  51. *    gadget labels: the code will invoke your hook in order to get the
  52. *    text required. Keystroke activation of gadgets is also taken care
  53. *    of, in fact the code will -- unless told not to do so -- assign keyboard
  54. *    shortcuts to the gadgets created all on its own. Every effort has been
  55. *    made to make the code reentrant, so it can be put into a shared library.
  56. *    If a user interface does not fit onto a screen provisions are made to
  57. *    choose a smaller font and to rescale the window contents until they fit.
  58. *    Last but not least the user interface code offers transparent extensions
  59. *    to the standard gadtools.library objects, such as LISTVIEW_KIND objects
  60. *    which respond to double-clicks or STRING_KIND objects which can be used
  61. *    to enter password text as they will not display the characters entered.
  62. *
  63. *
  64. *    1.2 Distribution
  65. *
  66. *    The code is *free*, you don't need to pay any money to use it, nor
  67. *    do you need to quote my name in the documentation, the program or
  68. *    anywhere else. You are allowed to make changes to the code, but if
  69. *    you stumble across any bugs or even know how to fix them, please
  70. *    let me know. It does not matter whether you intend to sell a program
  71. *    to use the code, use the code in shareware, gift-ware, freeware or
  72. *    etc.-ware programs: the code still remains royalty-free.
  73. *
  74. *
  75. *    1.3 Caveats
  76. *
  77. *    The code is pretty large, about 80K-100K bytes in size. Not all
  78. *    gadtools.library type objects are supported, notably
  79. *    GENERIC_KIND objects. The code is not as flexible as
  80. *    gadtools.library, so certain things which are easily done using
  81. *    gadtools.library may be pretty difficult or even impossible.
  82. *    The code is written entirely in `C' and requires SAS/C to
  83. *    compile. Some parts of the code are highly recursive; I haven't
  84. *    tested how much stack they might require in certain cases,
  85. *    but I recommend that you don't overuse the grouping feature.
  86. *    The data structures required to create and maintain the
  87. *    user interface are huge, a single window might require more
  88. *    than 4K-6K of memory. Proportional font support only works
  89. *    well starting with Kickstart v39 and up, v2.04 will probably
  90. *    not look quite that pretty.
  91. *
  92. *
  93. *    2. Programming
  94. *
  95. *    2.1 Client libraries required for link library version
  96. *
  97. *    You need to have SysBase and GadToolsBase initialized in order to make
  98. *    use of the code, i.e. your code has to do
  99. *    WaitPort()...GT_GetIMsg()...GT_ReplyIMsg all on its own. The code makes
  100. *    use of the memory pools introduced in exec.library v39, but calls the
  101. *    equivalent routines in amiga.lib. Note: as of this writing the pools
  102. *    code in amiga.lib v40.14 is broken, so you need to link with Mike
  103. *    Sinz' fixed pools.lib.
  104. *
  105. *
  106. *    2.2 Invocation procedure
  107. *
  108. *    The typical invocation procedure looks roughly like this:
  109. *
  110. *       LT_Init();    // only for link library version
  111. *       :
  112. *       :
  113. *          LT_CreateHandleTags();
  114. *             LT_New();
  115. *             :
  116. *             :
  117. *             LT_New();
  118. *                LT_Build();
  119. *                   LT_HandleInput();
  120. *          LT_DeleteHandle();
  121. *       :
  122. *       :
  123. *       LT_Exit();    // only for link library version
  124. *
  125. *    You need to call LT_Init() only once in your program, it will initialize
  126. *    the libraries and global data structures required by the user interface
  127. *    code. When you are finished with the user interface and your program is
  128. *    about to exit you need to call LT_Exit() or memory will get lost.
  129. *    Note that LT_Init() is not protected against multiple invocations. If
  130. *    called repeatedly memory will get lost which can never be reclaimed.
  131. *    However, LT_Exit() is protected against multiple invocations, you can
  132. *    also call it before ever giving LT_Init() a call, but I doubt this
  133. *    would make much sense. If you are using the shared gtlayout.library
  134. *    no call to LT_Init()/LT_Exit() is necessary as these calls are already
  135. *    wrapped into the library opening code.
  136. *       Before you can actually start building a window layout a call to
  137. *    LT_CreateHandleTags() needs to be made. You need to pass in a pointer
  138. *    to the Screen your user interface window is to be opened on and,
  139. *    optionally, a few tags to control the look and performance of the
  140. *    interface. *Never* close the screen in question before calling
  141. *    LT_DeleteHandle() or nasty things will happen. For public screens
  142. *    the code will try to lock the screen in question. With the handle
  143. *    LT_CreateHandleTags() returned you can call LT_New() to build the
  144. *    user interface. When finished a call to LT_Build() will finally
  145. *    open a window and place the gadgets inside. A pointer to the
  146. *    Window created will be returned, ready to be used for the
  147. *    WaitPort()...GT_GetIMsg()...LT_HandleInput()...GT_ReplyIMsg()
  148. *    loop. When finished, a call to LT_DeleteHandle() will close the
  149. *    window and release all the memory associated with it. The design
  150. *    of the interface code is similar to the corresponding calls in
  151. *    gadtools.library, i.e. you don't need to worry about LT_New()
  152. *    failing to allocate memory for the objects required. When it comes
  153. *    to LT_Build() the code will know about any trouble which would
  154. *    show up during previous invocations of LT_New(). In essence,
  155. *    if LT_Build() returns NULL something is wrong.
  156. *
  157. *
  158. *    2.3 Hierarchic grouping
  159. *
  160. *    The basic building block of the user interface is a group, either
  161. *    a horizontal or a vertical group. Adding gadgets or other objects
  162. *    to a horizontal group will place them side by side from left to
  163. *    right. A vertical group causes objects to be place from top to
  164. *    bottom in one straight line. Groups help to arrange objects
  165. *    neatly stacked, centered and properly aligned with other
  166. *    members of the group.
  167. *
  168. *    MUCHO IMPORTANTE: there is a bug lurking in the code which I never
  169. *    had the luck to find and fix. One would expect to create
  170. *    user interface structures like this:
  171. *
  172. *       <group start>
  173. *          <button>
  174. *          <list>
  175. *          <group start>
  176. *             <slider>
  177. *             <text>
  178. *          <group end>
  179. *          <button>
  180. *       <group end>
  181. *
  182. *    However, it is in fact not possible to mix gadgets and groups.
  183. *    Thus, the user interface structure would have to look like this:
  184. *
  185. *       <group start>
  186. *          <group start>
  187. *             <button>
  188. *             <list>
  189. *          <group end>
  190. *          <group start>
  191. *             <slider>
  192. *             <text>
  193. *          <group end>
  194. *          <group start>
  195. *             <button>
  196. *          <group end>
  197. *       <group end>
  198. *
  199. *    Or in other words: groups only mix with other groups.
  200. *
  201. *    You build groups using three different object types. In this
  202. *    context `object type' refers to a specific numeric value the
  203. *    LT_New() routine knows which will cause it to add another leaf
  204. *    to the user interface structure tree. Here is an example:
  205. *
  206. *       struct LayoutHandle *Handle;
  207. *
  208. *       if(Handle = LT_CreateHandleTags(NULL,
  209. *          LAHN_AutoActivate,FALSE,
  210. *       TAG_DONE))
  211. *       {
  212. *          struct Window *Window;
  213. *
  214. *          LT_New(Handle,
  215. *             LA_Type,      VERTICAL_KIND,  \* A vertical group. *\
  216. *             LA_LabelText, "Main group",   \* Group title text. *\
  217. *          TAG_DONE);
  218. *          {
  219. *             LT_New(Handle,
  220. *                LA_Type,      BUTTON_KIND, \* A plain button. *\
  221. *                LA_LabelText, "A button",
  222. *                LA_ID,        11,
  223. *             TAG_DONE);
  224. *
  225. *             LT_New(Handle,
  226. *                LA_Type,      XBAR_KIND,   \* A separator bar. *\
  227. *             TAG_DONE);
  228. *
  229. *             LT_New(Handle,
  230. *                LA_Type,      BUTTON_KIND, \* A plain button. *\
  231. *                LA_LabelText, "Another button",
  232. *                LA_ID,        22,
  233. *             TAG_DONE);
  234. *
  235. *             LT_New(Handle,
  236. *                LA_Type,      END_KIND,    \* This ends the current group. *\
  237. *             TAG_DONE);
  238. *          }
  239. *
  240. *          if(Window = LT_Build(Handle,
  241. *            LAWN_Title,     "Window title",
  242. *            LAWN_IDCMP,     IDCMP_CLOSEWINDOW,
  243. *            WA_CloseGadget, TRUE,
  244. *          TAG_DONE))
  245. *          {
  246. *              struct IntuiMessage *Message;
  247. *              ULONG                MsgQualifier,
  248. *                                   MsgClass;
  249. *              UWORD                MsgCode;
  250. *              struct Gadget       *MsgGadget;
  251. *              BOOL                 Done = FALSE;
  252. *
  253. *              do
  254. *              {
  255. *                  WaitPort(Window->UserPort);
  256. *
  257. *                  while(Message = GT_GetIMsg(Window->UserPort))
  258. *                  {
  259. *                     MsgClass     = Message->Class;
  260. *                     MsgCode      = Message->Code;
  261. *                     MsgQualifier = Message->Qualifier;
  262. *                     MsgGadget    = Message->IAddress;
  263. *
  264. *                     GT_ReplyIMsg(Message);
  265. *
  266. *                     LT_HandleInput(Handle,MsgQualifier,&MsgClass,
  267. *                         &MsgCode,&MsgGadget);
  268. *
  269. *                     switch(MsgClass)
  270. *                     {
  271. *                        case IDCMP_CLOSEWINDOW:
  272. *
  273. *                            Done = TRUE;
  274. *                            break;
  275. *
  276. *                        case IDCMP_GADGETUP:
  277. *
  278. *                            switch(MsgGadget->GadgetID)
  279. *                            {
  280. *                                case 11: printf("First gadget\n");
  281. *                                         break;
  282. *
  283. *                                case 22: printf("Second gadget\n");
  284. *                                         break;
  285. *                            }
  286. *
  287. *                            break;
  288. *                     }
  289. *                  }
  290. *              }
  291. *              while(!Done);
  292. *          }
  293. *
  294. *          LT_DeleteHandle(Handle);
  295. *       }
  296. *
  297. *    The example creates one single group, places a few objects inside,
  298. *    calls the layout routine, handles the input and finally cleans
  299. *    things up again. This example also shows that you *need* at
  300. *    least one group in your tree (to form the root) in order to get
  301. *    things to work.
  302. *       The input loop requires you to call LT_HandleInput() in order
  303. *    to get the user interface code to filter out certain events and
  304. *    to update internal information. The data passed in must have
  305. *    been processed via the gadtools.library routines. You *must not*
  306. *    call LT_HandleInput() before GT_ReplyIMsg() is called since the
  307. *    routine may call intuition.library and gadtools.library routines
  308. *    which in turn might lead to a system lock-up if the message
  309. *    has not been processed yet. The first thing to do after LT_HandleInput()
  310. *    has done whatever was necessary to the data you passed in is
  311. *    examine the MsgClass variable. The user interface code will
  312. *    `fake' certain message events using the variables passed in,
  313. *    *do not* use any other data gathered from the original
  314. *    IntuiMessage. The MsgClass may include event types you did
  315. *    not ask for, i.e. the IDCMP flags of the window opened
  316. *    will be set according to the objects you added to the window.
  317. *    Also, the IDCMP_IDCMPUPDATE message class will show up for
  318. *    certain objects. More on this later in this document.
  319. *
  320. *
  321. *    2.4 Setting and getting object attributes
  322. *
  323. *    The mechanism to update and query object attributes does not
  324. *    exactly match the familiar gadtools.library interface. In
  325. *    fact, the routine to change gadget attributes will forward
  326. *    the tagitem list passed in to gadtools.library/GT_SetGadgetAttrs().
  327. *    On the other hand the routine to query object attributes does
  328. *    not work like gadtools.library/GT_GetGadgetAttrs(). The
  329. *    user interface code assumes that all objects it can handle and
  330. *    create posess certain attributes unique to the type of the
  331. *    object in question. For example, the unique attribute of a
  332. *    STRING_KIND object would be a pointer to the string it
  333. *    `contains'. The unique attribute of a SLIDER_KIND object is
  334. *    the current slider position. The LT_GetAttributes() routine
  335. *    will return this attribute, but also accept a tagitem list
  336. *    to fill in for certain special tag values.
  337. *
  338. *
  339. *    2.5 Extra data
  340. *
  341. *    Once a LayoutHandle has been created the interface code will
  342. *    provide you with a number of information concerning the screen
  343. *    the handle has been attached to. This information includes
  344. *    the DrawInfo structure of the screen, the VisualInfo data
  345. *    and the Screen address. This information is read-only.
  346. *
  347. *
  348. *    2.6 Menus
  349. *
  350. *    With a LayoutHandle available a routine called LT_LayoutMenuTags()
  351. *    will create a standard Intuition menu structure via gadtools.library
  352. *    which can be passed to LT_Build(). Note that this
  353. *    routine does not modify any data passed in, it does neither
  354. *    attach the menu created to the LayoutHandle passed in,
  355. *    nor does it change the NewMenu table.
  356. *
  357. *
  358. *    2.7 Localization
  359. *
  360. *    All object and menu creation routines support localization via
  361. *    a Hook callback interface, i.e. you can pass a pointer to an
  362. *    initialized Hook structure to LT_CreateHandleTags() which will
  363. *    later be used to supply label and list text for objects
  364. *    created. The Hook callback routine is called in the following
  365. *    fashion:
  366. *
  367. *       String = HookFunc(struct Hook *Hook,struct LayoutHandle *Handle,LONG ID)
  368. *         D0                            A0                         A2        A1
  369. *
  370. *    Or in other words: a locale string ID is passed in, the routine is supposed
  371. *    to look up the string to match this ID and to return it.
  372. *
  373. *
  374. *    2.8 Object types to generate IDCMP_IDCMPUPDATE events
  375. *
  376. *    Certain objects convey extra information which is merged into the `fake'
  377. *    input stream passed to the client calling LT_HandleInput(). These objects
  378. *    are:
  379. *
  380. *       STRING_KIND
  381. *       TEXT_KIND
  382. *       PALETTE_KIND
  383. *
  384. *          The user pressed the `select' button which belongs
  385. *          to this gadget. The MsgGadget pointer indicates the
  386. *          STRING_KIND/TEXT_KIND/PALETTE_KIND object the `select'
  387. *          button belongs to.
  388. *
  389. *       LISTVIEW_KIND
  390. *
  391. *          The user double-clicked on an entry. The entry number
  392. *          is returned in the MsgCode variable. The MsgGadget
  393. *          pointer indicates the LISTVIEW_KIND object the user
  394. *          has clicked on.
  395. *
  396. *
  397. *    2.9 Keystroke activation
  398. *
  399. *    Unless forbidden via the the LA_NoKey tag item the user interface
  400. *    code will pick the keyboard shortcuts for all gadgets on its own.
  401. *    The currently active global console keymap will be checked at the
  402. *    time when LT_Init() is called in order to make sure subsequent
  403. *    calls to LT_Build() will use only keys the user can press on
  404. *    the keyboard. Double-dead keys are also excluded from the
  405. *    table created. This avoids problems with gadget labels such as
  406. *    "éééé" which would require the user to hit two keys in a row to
  407. *    activate the gadget.
  408. *       If the window created happens to feature a close gadget
  409. *    pressing the `Esc' key will cause the client to receive
  410. *    an IDCMP_CLOSEWINDOW event.
  411. *       A single LISTVIEW_KIND object may receive special treatment
  412. *    if the LALV_CursorKey tag is used: the user will be able to
  413. *    operate the listview using the cursor keys. Note: this
  414. *    will also keep the user interface code from choosing a
  415. *    special keystroke from the gadget label.
  416. *       The user will be able to operate a single BUTTON_KIND
  417. *    object using the return key if the LABT_ReturnKey tag is
  418. *    used. A recessed frame will be drawn around the button hit
  419. *    box to indicate its special status.
  420. *       Pressing the Tab key can be bound to operate a cycle or
  421. *    mx kind object.
  422. *
  423. *    3. Credits
  424. *
  425. *    The original design is based upon the user interface layout code used by
  426. *    `term' 3.1. I put the first version of the layout routines together back
  427. *    in Summer 1993 when I wanted to write the follow-up to `term' v3.4.
  428. *
  429. *    Martin Taillefer rewrote large parts of the code, added new routines and
  430. *    generally improved the performance of the layout process. I owe Martin
  431. *    much for the ideas he put into the library.
  432. *
  433. *    Kai Iske, Christoph Feck, Stefan Becker, Michael Barsoom, Sven Stullich
  434. *    and Mark Ritter helped to iron out the remaining bugs and piled up bug
  435. *    reports and enhancement requests.
  436. *
  437. ******************************************************************************
  438. *
  439. */
  440.  
  441. /*****************************************************************************/
  442.  
  443.     // First executable location of this library, must return an
  444.     // error to the unsuspecting caller
  445.  
  446. LONG
  447. ReturnError(VOID)
  448. {
  449.     return(-1);
  450. }
  451.  
  452. /*****************************************************************************/
  453.  
  454. struct GTLayoutBase
  455. {
  456.     struct Library            LibNode;
  457.  
  458.     struct Library *        ExecBase;
  459.     BPTR                    LibSegment;
  460.     struct SignalSemaphore    LockSemaphore;
  461. };
  462.  
  463. #define SysBase GTLayoutBase->ExecBase
  464.  
  465. /*****************************************************************************/
  466.  
  467. STATIC struct Library * LIBENT
  468. LibInit(
  469.     REG(d0) struct GTLayoutBase *    GTLayoutBase,
  470.     REG(a0) BPTR                    Segment,
  471.     REG(a6) struct ExecBase *        ExecBase)
  472. {
  473.     struct Library *result = NULL;
  474.  
  475.     GTLayoutBase->ExecBase = (struct Library *)ExecBase;
  476.  
  477. #if !defined(CPU_ANY) && !defined(CPU_any)
  478.     if(ExecBase->AttnFlags & AFF_68020)
  479. #endif    // CPU_ANY
  480.  
  481.     if(ExecBase->LibNode.lib_Version >= 37)
  482.     {
  483.         GTLayoutBase->LibNode.lib_Revision = REVISION;
  484.  
  485.         GTLayoutBase->LibSegment = Segment;
  486.  
  487.         InitSemaphore(>LayoutBase->LockSemaphore);
  488.  
  489.         result = GTLayoutBase;
  490.     }
  491.  
  492.         /* If the initialization failed, we will have to release
  493.          * the memory allocated for the library base and
  494.          * vector. This is an often overlooked requirement for
  495.          * RTF_AUTOINIT libraries/resources/devices which
  496.          * return NULL in the initialization procedure.
  497.          */
  498.  
  499.     if(result == NULL)
  500.     {
  501.         FreeMem((BYTE *)GTLayoutBase - GTLayoutBase->LibNode.lib_NegSize,
  502.                 GTLayoutBase->LibNode.lib_NegSize + GTLayoutBase->LibNode.lib_PosSize);
  503.     }
  504.  
  505.     return(result);
  506. }
  507.  
  508. /*****************************************************************************/
  509.  
  510. STATIC struct Library * LIBENT
  511. LibOpen(REG(a6) struct GTLayoutBase *GTLayoutBase)
  512. {
  513.     struct Library *result = GTLayoutBase;
  514.     UWORD openCnt;
  515.  
  516.     openCnt = GTLayoutBase->LibNode.lib_OpenCnt;
  517.  
  518.     GTLayoutBase->LibNode.lib_OpenCnt++;
  519.     GTLayoutBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
  520.  
  521.     ObtainSemaphore(>LayoutBase->LockSemaphore);
  522.  
  523.     if(openCnt == 0)
  524.     {
  525.         if(!LT_Init())
  526.         {
  527.             LT_Exit();
  528.  
  529.             result = NULL;
  530.         }
  531.     }
  532.  
  533.     ReleaseSemaphore(>LayoutBase->LockSemaphore);
  534.  
  535.     if(result == NULL)
  536.         GTLayoutBase->LibNode.lib_OpenCnt--;
  537.  
  538.     return(result);
  539. }
  540.  
  541. /*****************************************************************************/
  542.  
  543. STATIC BPTR LIBENT
  544. LibExpunge(REG(a6) struct GTLayoutBase *GTLayoutBase)
  545. {
  546.     BPTR result;
  547.  
  548.     if(GTLayoutBase->LibNode.lib_OpenCnt == 0 && GTLayoutBase->LibSegment != NULL)
  549.     {
  550.         result = GTLayoutBase->LibSegment;
  551.  
  552.         Remove((struct Node *)GTLayoutBase);
  553.  
  554.         FreeMem((BYTE *)GTLayoutBase - GTLayoutBase->LibNode.lib_NegSize,
  555.                 GTLayoutBase->LibNode.lib_NegSize + GTLayoutBase->LibNode.lib_PosSize);
  556.     }
  557.     else
  558.     {
  559.         result = NULL;
  560.  
  561.         GTLayoutBase->LibNode.lib_Flags |= LIBF_DELEXP;
  562.     }
  563.  
  564.     return(result);
  565. }
  566.  
  567. /*****************************************************************************/
  568.  
  569. STATIC BPTR LIBENT
  570. LibClose(REG(a6) struct GTLayoutBase *GTLayoutBase)
  571. {
  572.     BPTR result;
  573.  
  574.     ObtainSemaphore(>LayoutBase->LockSemaphore);
  575.  
  576.     if(GTLayoutBase->LibNode.lib_OpenCnt == 1)
  577.     {
  578.         LT_Exit();
  579.     }
  580.  
  581.     GTLayoutBase->LibNode.lib_OpenCnt--;
  582.  
  583.     ReleaseSemaphore(>LayoutBase->LockSemaphore);
  584.  
  585.     if(GTLayoutBase->LibNode.lib_OpenCnt == 0 && (GTLayoutBase->LibNode.lib_Flags & LIBF_DELEXP))
  586.         result = LibExpunge(GTLayoutBase);
  587.     else
  588.         result = NULL;
  589.  
  590.     return(result);
  591. }
  592.  
  593. /*****************************************************************************/
  594.  
  595. STATIC LONG
  596. LibNull(VOID)
  597. {
  598.     return(NULL);
  599. }
  600.  
  601. /*****************************************************************************/
  602.  
  603. STATIC const APTR LibVectors[] =
  604. {
  605.     LibOpen,
  606.     LibClose,
  607.     LibExpunge,
  608.     LibNull,
  609.  
  610.     LT_LevelWidth,
  611.     LT_DeleteHandle,
  612.     LT_CreateHandle,
  613.     LT_CreateHandleTagList,
  614.     LT_Rebuild,
  615.     LT_HandleInput,
  616.     LT_BeginRefresh,
  617.     LT_EndRefresh,
  618.     LT_GetAttributesA,
  619.     LT_SetAttributesA,
  620.     LT_AddA,
  621.     LT_NewA,
  622.     LT_EndGroup,
  623.     LT_LayoutA,
  624.     LT_LayoutMenusA,
  625.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  626.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  627.     LibNull,    /* There used to be a FRACTION_KIND support routine here. */
  628.     LT_LabelWidth,
  629.     LT_LabelChars,
  630.     LT_LockWindow,
  631.     LT_UnlockWindow,
  632.     LT_DeleteWindowLock,
  633.     LT_ShowWindow,
  634.     LT_Activate,
  635.     LT_PressButton,
  636.     LT_GetCode,
  637.     LT_GetIMsg,
  638.     LT_ReplyIMsg,
  639.     LT_BuildA,
  640.     LT_RebuildTagList,
  641.     LT_UpdateStrings,
  642.  
  643. #ifdef DO_MENUS
  644.     LT_DisposeMenu,
  645.     LT_NewMenuTemplate,
  646.     LT_NewMenuTagList,
  647.     LT_MenuControlTagList,
  648.     LT_GetMenuItem,
  649.     LT_FindMenuCommand,
  650. #else
  651.     LibNull,
  652.     LibNull,
  653.     LibNull,
  654.     LibNull,
  655.     LibNull,
  656.     LibNull,
  657. #endif /* DO_MENUS */
  658.  
  659.     LT_NewLevelWidth,
  660.     LT_Refresh,
  661.     LT_CatchUpRefresh,
  662.     LT_GetWindowUserData,
  663.  
  664.     (APTR)-1
  665. };
  666.  
  667. /*****************************************************************************/
  668.  
  669. struct LibInitData
  670. {
  671.     ULONG    lid_DataSize;
  672.     APTR    lid_Table;
  673.     APTR    lid_Data;
  674.     APTR    lid_InitRoutine;
  675. };
  676.  
  677. const struct LibInitData LibInitTab =
  678. {
  679.     sizeof(struct GTLayoutBase),
  680.     LibVectors,
  681.     NULL,
  682.     LibInit
  683. };
  684.  
  685. /*****************************************************************************/
  686.  
  687. #ifdef CPU_ANY
  688. #define CPU_TYPE "Generic 68k version"
  689. #else
  690. #define CPU_TYPE "MC68020/030/040/060 version"
  691. #endif    /* CPU_ANY */
  692.  
  693. const STRPTR VersTag = "$VER: " VERS " (" DATE ") " CPU_TYPE;
  694.  
  695. /*****************************************************************************/
  696.  
  697. const struct Resident RomTag =
  698. {
  699.     RTC_MATCHWORD,
  700.     &RomTag,
  701.     &RomTag + 1,
  702.     RTF_AUTOINIT,
  703.     VERSION,
  704.     NT_LIBRARY,
  705.     0,
  706.     "gtlayout.library",
  707.     VSTRING,
  708.     &LibInitTab
  709. };
  710.